package io.renren.modules.calculator.service;

import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Stack;

@Service
public class CalculatorService {

    public BigDecimal calculate(String expression, int precision) {
        try {
            // 1. 预处理表达式
            expression = preprocessExpression(expression);

            // 2. 将中缀表达式转换为后缀表达式
            String postfix = infixToPostfix(expression);

            // 3. 计算后缀表达式
            return evaluatePostfix(postfix, precision);
        } catch (Exception e) {
            throw new IllegalArgumentException("表达式计算错误: " + e.getMessage());
        }
    }

    private String preprocessExpression(String expr) {
        // 去除所有空白字符
        expr = expr.replaceAll("\\s+", "");

        // 替换数学函数和常量
        return expr.replaceAll("sin\\(", "Math.sin\\(")
                .replaceAll("cos\\(", "Math.cos\\(")
                .replaceAll("tan\\(", "Math.tan\\(")
                .replaceAll("ln\\(", "Math.log\\(")
                .replaceAll("π", "Math.PI");
    }

    private String infixToPostfix(String infix) {
        // 实现中缀转后缀表达式（完整实现）
        StringBuilder output = new StringBuilder();
        Stack<Character> stack = new Stack<>();

        for (int i = 0; i < infix.length(); i++) {
            char c = infix.charAt(i);

            if (Character.isDigit(c) || c == '.') {
                // 处理数字（包括多位数和小数）
                while (i < infix.length() &&
                        (Character.isDigit(infix.charAt(i)) || infix.charAt(i) == '.')) {
                    output.append(infix.charAt(i++));
                }
                output.append(" ");
                i--;
            }
            else if (Character.isLetter(c)) {
                // 处理函数（如Math.sin）
                while (i < infix.length() &&
                        (Character.isLetter(infix.charAt(i)) || infix.charAt(i) == '.')) {
                    output.append(infix.charAt(i++));
                }
                output.append(" ");
                i--;
            }
            else if (c == '(') {
                stack.push(c);
            }
            else if (c == ')') {
                while (!stack.isEmpty() && stack.peek() != '(') {
                    output.append(stack.pop()).append(" ");
                }
                stack.pop(); // 弹出'('
            }
            else {
                // 处理运算符
                while (!stack.isEmpty() && precedence(c) <= precedence(stack.peek())) {
                    output.append(stack.pop()).append(" ");
                }
                stack.push(c);
            }
        }

        while (!stack.isEmpty()) {
            output.append(stack.pop()).append(" ");
        }

        return output.toString().trim();
    }

    private int precedence(char op) {
        switch (op) {
            case '+':
            case '-':
                return 1;
            case '*':
            case '/':
                return 2;
            case '^':
                return 3;
            default:
                return 0;
        }
    }

    private BigDecimal evaluatePostfix(String postfix, int precision) {
        MathContext mc = new MathContext(precision, RoundingMode.HALF_UP);
        Stack<BigDecimal> stack = new Stack<>();
        String[] tokens = postfix.split("\\s+");

        for (String token : tokens) {
            if (token.matches("-?\\d+(\\.\\d+)?")) {
                // 数字直接入栈
                stack.push(new BigDecimal(token));
            }
            else if (token.startsWith("Math.")) {
                // 处理函数调用
                BigDecimal operand = stack.pop();
                double result = evaluateMathFunction(token, operand.doubleValue());
                stack.push(new BigDecimal(result, mc));
            }
            else {
                // 处理运算符
                BigDecimal b = stack.pop();
                BigDecimal a = stack.pop();
                switch (token) {
                    case "+": stack.push(a.add(b, mc)); break;
                    case "-": stack.push(a.subtract(b, mc)); break;
                    case "*": stack.push(a.multiply(b, mc)); break;
                    case "/": stack.push(a.divide(b, mc)); break;
                    default: throw new IllegalArgumentException("未知运算符: " + token);
                }
            }
        }

        return stack.pop();
    }

    private double evaluateMathFunction(String func, double value) {
        if (func.equals("Math.sin")) return Math.sin(value);
        if (func.equals("Math.cos")) return Math.cos(value);
        if (func.equals("Math.tan")) return Math.tan(value);
        if (func.equals("Math.log")) return Math.log(value);
        return 1.0;//throw new IllegalArgumentException("未知函数: " + func);
    }
}